package com.yeskery.nut.util;

import com.yeskery.nut.core.KeyAndValue;
import com.yeskery.nut.core.NutException;
import com.yeskery.nut.core.PathMetadata;

import java.util.ArrayList;
import java.util.List;
import java.util.Stack;
import java.util.regex.Pattern;

/**
 * 路径工具类
 * @author sprout
 * 2022-06-14 11:03
 */
public class PathUtils {

    /** 开始符号 */
    private static final char START_SYMBOL = '{';

    /** 结束符号 */
    private static final char END_SYMBOL = '}';

    /** 路径参数正则表达式管道符正则 */
    private static final String PIPELINE_SYMBOL_PATTERN = "\\|";

    /** 路径参数正则表达式管道符 */
    private static final char PIPELINE_SYMBOL = '|';

    /** 路径参数正则表达式管道符 */
    private static final String PIPELINE_SYMBOL_STR = String.valueOf(PIPELINE_SYMBOL);

    /** 默认的路径正则表达式 */
    private static final String DEFAULT_PATH_PATTERN_STR = "\\S+";

    /**
     * 私有化构造方法
     */
    private PathUtils() {
    }

    /**
     * 将路径转换为路径元数据
     * @param path 路径
     * @return 路径元数据
     */
    @SuppressWarnings("unchecked")
    public static PathMetadata parse(String path) {
        if (StringUtils.isEmpty(path)) {
            return null;
        }
        List<PathMetadataIndex> pathMetadataIndexList = new ArrayList<>();
        StringBuilder basePathBuilder = new StringBuilder();
        Stack<Integer> stack = new Stack<>();
        for (int i = 0; i < path.length(); i++) {
            char c = path.charAt(i);
            basePathBuilder.append(c);
            if (c == START_SYMBOL) {
                stack.push(i);
            } else if (c == END_SYMBOL) {
                Integer startIndex = stack.pop();
                if (stack.empty() && startIndex != null) {
                    PathMetadataIndex pathMetadataIndex = new PathMetadataIndex();
                    pathMetadataIndex.startIndex = startIndex;
                    pathMetadataIndex.endIndex = i;
                    pathMetadataIndex.expression = path.substring(startIndex, i + 1);
                    pathMetadataIndexList.add(pathMetadataIndex);
                    if (!StringUtils.isEmpty(pathMetadataIndex.expression)) {
                        int j = pathMetadataIndex.expression.indexOf(PIPELINE_SYMBOL);
                        if (j != -1) {
                            basePathBuilder.delete(startIndex + j, i);
                        }
                    }
                }
            }
        }

        if (pathMetadataIndexList.isEmpty()) {
            return new PathMetadata(path);
        }
        KeyAndValue<String, Pattern>[] keyAndValues = new KeyAndValue[pathMetadataIndexList.size()];
        StringBuilder pathPatternBuilder = new StringBuilder();
        PathMetadataIndex lastPathMetadataIndex = null;
        for (int i = 0; i < pathMetadataIndexList.size(); i++) {
            PathMetadataIndex pathMetadataIndex = pathMetadataIndexList.get(i);
            if (pathMetadataIndex.startIndex + 1 >= pathMetadataIndex.endIndex) {
                throw new NutException("Wrong Path Index At Expression [" + pathMetadataIndex.expression + "].");
            }
            String expression = pathMetadataIndex.expression.substring(1, pathMetadataIndex.expression.length() - 1);
            String pattern = DEFAULT_PATH_PATTERN_STR;
            String name = expression.trim();
            if (expression.contains(PIPELINE_SYMBOL_STR)) {
                String[] splits = expression.split(PIPELINE_SYMBOL_PATTERN);
                if (splits.length != 2) {
                    throw new NutException("Wrong Path Pipeline At Expression [" + pathMetadataIndex.expression + "].");
                }
                name = splits[0].trim();
                pattern = splits[1].trim();
            }
            keyAndValues[i] = new KeyAndValue<>(name, Pattern.compile(pattern));

            int startIndex = lastPathMetadataIndex == null ? 0 : lastPathMetadataIndex.endIndex + 1;
            pathPatternBuilder.append(path, startIndex, pathMetadataIndex.startIndex);
            pathPatternBuilder.append("(").append(pattern).append(")");
            lastPathMetadataIndex = pathMetadataIndex;
        }

        return new PathMetadata(true, path, basePathBuilder.toString(), Pattern.compile(pathPatternBuilder.toString()), keyAndValues);
    }

    /**
     * 路径数据索引对象
     * @author sprout
     * 2022-06-14 12:40
     */
    private static class PathMetadataIndex {
        /** 开始索引 */
        private int startIndex;
        /** 结束索引 */
        private int endIndex;
        /** 参数表达式 */
        private String expression;
    }
}
